// 参考链接：https://www.jb51.net/html5/716686.html

// 可选模式
// 移动、缩放
const MOVE_MODE = 0;
// 画笔
const LINE_MODE = 1;
// 橡皮擦
const ERASER_MODE = 2;

// 最大最小缩放倍数
const SCALE_MIN = 0.1;
const SCALE_MAX = 2;
// 画布缩放，默认为1
let canvasScale = 1;

// 画笔宽度
let lineWidth = 5;
let lineColor = 'red';

// 操作历史，用于撤销、恢复
let canvasHistory = [];
let canvasCurrentHistory = 0;

// 画布容器
let wrapper = document.getElementById('canvasWrapper');
// 画布
let canvas = document.getElementById('canvas');

// 当前位移距离
let transX = 0;
let transY = 0;

// 上次位移结束时的位移距离
let prevX = 0;
let prevY = 0;

// 模式，默认移动
let mouseMode = MOVE_MODE
// 根据模式绑定事件
handleCanvas();

// base64转图片
function dataURLtoFile(dataurl, filename = 'file') {
    let arr = dataurl.split(',');
    let mime = arr[0].match(/:(.*?);/)[1];
    let suffix = mime.split('/')[1];
    let bstr = atob(arr[1]);
    let n = bstr.length;
    let u8arr = new Uint8Array(n);
    while (n--) {
        u8arr[n] = bstr.charCodeAt(n);
    }
    return new File([u8arr], `${filename}.${suffix}`, {
        type: mime
    })
}

// 重置图片
function resetImg() {
    canvasHistory = [];
    canvasCurrentHistory = 0;
    canvasScale = 1;
    transX = 0;
    transY = 0;
    prevX = 0;
    prevY = 0;
}

// 重置图片位置
function resetImgPos() {
    canvasScale = 1;
    transX = 0;
    transY = 0;
    prevX = 0;
    prevY = 0;
    canvas.style.transform = `scale(${canvasScale}, ${canvasScale}) translate(${transX}px, ${transY}px)`;
}

// 选择图片
function selectImg() {
    let src = window.event.target.value;
    fillImg(src);
    resetImg();
    // 初始化
    handleCanvas();
}

// 选择模式
function selectMode() {
    mouseMode = +window.event.target.value;
    switch (mouseMode) {
        case MOVE_MODE:
            canvas.style.cursor = 'move';
            wrapper.style.cursor = 'move';
            break;
        case LINE_MODE:
            canvas.style.cursor = "url('http://cdn.algbb.cn/pencil.ico') 6 26, pointer";
            wrapper.style.cursor = 'default';
            break;
        case ERASER_MODE:
            canvas.style.cursor = "url('http://cdn.algbb.cn/eraser.ico') 6 26, pointer";
            wrapper.style.cursor = 'default';
            break;
        default:
            canvas.style.cursor = 'default';
            wrapper.style.cursor = 'default';
            break;
    }
    // 重新初始化
    handleCanvas();
}

// 选择画笔颜色
function selectPencilColor() {
    lineColor = window.event.target.value;
}

// 选择画笔宽度
function selectPencilWidth() {
    lineWidth = window.event.target.value;
}

// 设置画布平移、缩放
function handleCanvasTrans(newScale) {
    canvasScale = newScale || canvasScale;
    let canvas = document.getElementById('canvas');
    canvas.style.transform = `scale(${canvasScale}, ${canvasScale}) translate(${transX}px, ${transY}px)`;
}

// 撤销与恢复
// 若当前状态处于第一个位置，则不允许撤销
// 若当前状态处于最后一个位置，则不允许恢复
// 如果当前撤销了，然而更新了状态，则取当前状态为最新的状态（也就是说不允许恢复了，这个刚更新的状态就是最新的）
// 撤销
function handleRollBack() {
    let isFirst = canvasCurrentHistory <= 1;
    if (isFirst) {
        return false;
    }
    canvasCurrentHistory -= 1;
}

// 恢复
function handleRollForward() {
    let isLast = canvasCurrentHistory == canvasHistory.length;
    if (isLast) {
        return false
    }
    canvasCurrentHistory += 1;
}

// 清空
function handleClear() {
    let ctx = canvas.getContext('2d');
    if (!wrapper || !canvas || !ctx || canvasCurrentHistory == 0) {
        return false
    }
    let needClear = window.confirm('确定清空？')
    if (needClear) {
        canvasHistory = [];
        canvasCurrentHistory = 1;
    }
}

// 填充图片
function fillImg(src) {
    let img = new Image();
    img.src = src || './imgs/th0922.jpg';

    img.onload = () => {
        canvas.width = wrapper.offsetWidth || img.width;
        canvas.height = wrapper.offsetHeight || img.height;

        // 绘制图片，将图片设置为canvas的背景图片橡皮擦的效果才能显示
        canvas.style.background = `url(${img.src})`;
        canvas.style.backgroundSize = '100% 100%';
        let ctx = canvas.getContext('2d');
        ctx.drawImage(img, 0, 0, canvas.width, canvas.height);
        ctx.strokeStyle = lineColor;
        ctx.lineWidth = lineWidth;
        ctx.lineJoin = 'round';
        ctx.lineCap = 'round';

        // 设置变化中心
        canvas.style.transformOrigin = `${wrapper.offsetWidth / 2}px ${wrapper.offsetHeight / 2}px`;
        // 清除上一次变化结果
        canvas.style.transform = '';

        // 保存历史
        let imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
        canvasHistory = [imageData];
        canvasCurrentHistory += 1;
    };
}

// 转换屏幕坐标和画布坐标
function generateLinePoint(x, y) {
    // canvas父容器尺寸
    let wrapperWidth = wrapper.offsetWidth || 0;
    let wrapperHeight = wrapper.offsetHeight || 0;

    // 缩放位移坐标变化
    // (transformOrigin - downX) / scale * (scale - 1) + downY - translateX = pointX
    let pointX = (wrapperWidth / 2 - x) / canvasScale * (canvasScale - 1) + x - transX;
    let pointY = (wrapperHeight / 2 - y) / canvasScale * (canvasScale - 1) + y - transY;

    return {
        x: pointX,
        y: pointY
    }
}

// 监听canva画布的鼠标事件
function handleCanvas() {
    let ctx = canvas.getContext('2d');
    if (!wrapper || !canvas || !ctx) {
        return false;
    }
    // 清除上一次设置的监听事件，避免参数错误
    wrapper.onmousedown = null;
    wrapper.onmousedown = function () {
        let downX = window.event.offsetX;
        let downY = window.event.offsetY;
        // 区分选择的鼠标模式：移动、画笔、橡皮擦
        switch (mouseMode) {
            case MOVE_MODE:
                handleMoveMode(downX, downY);
                break;
            case LINE_MODE:
                handleLineMode(downX, downY);
                break;
            case ERASER_MODE:
                handleEraserMode(downX, downY);
                break;
            default:
                break;
        }
    }

    // 监听鼠标滚轮事件，缩放画布
    wrapper.onwheel = null;
    wrapper.onwheel = function () {
        let deltaY = window.event.deltaY;
        let deltaScale = deltaY > 0 ? -0.1 : 0.1
        let newScale = (canvasScale * 10 + deltaScale * 10) / 10
        if (newScale < SCALE_MIN || newScale > SCALE_MAX) {
            // 设置画布缩放
            handleCanvasTrans(newScale);
        }
    };
}

// 移动模式：监听鼠标事件
function handleMoveMode(downX, downY) {
    // 移动模式
    if (!wrapper || !canvas || mouseMode !== 0) {
        return false;
    }

    // 为容器添加mousemove事件
    wrapper.onmousemove = function () {
        let moveX = window.event.pageX;
        let moveY = window.event.pageY;

        // 更新现在位移距离，最后的位置坐标 + 位移
        transX = prevX + +(moveX - downX);
        transY = prevY + +(moveY - downY);

        // 更新画布位置
        handleCanvasTrans();
        console.log('move: ', [transX, transY])
    };

    // mouseup
    wrapper.onmouseup = function () {
        let upX = window.event.pageX;
        let upY = window.event.pageY;

        // 取消事件监听
        wrapper.onmousemove = null;
        wrapper.onmouseup = null;

        // 鼠标抬起时，更新上一次结束位置
        prevX = prevX + +(upX - downX);
        prevY = prevY + +(upY - downY);
        console.log('mouseup: ', [prevX, prevY])
    };
}

// 画笔模式：监听鼠标事件
function handleLineMode(downX, downY) {
    let ctx = canvas.getContext('2d');
    if (!wrapper || !canvas || !ctx) {
        return false;
    }

    let offsetTop = canvas.offsetTop;
    let offsetLeft = canvas.offsetLeft;
    // 减去画布偏移距离
    downX -= offsetLeft;
    downY -= offsetTop;

    let { x, y } = generateLinePoint(downX, downY);
    // 使用不同的 globalCompositeOperation 值绘制矩形
    // source-over: 目标图像位于源图像之下
    // destination-over: 目标图像位于源图像之上
    ctx.globalCompositeOperation = 'source-over';

    ctx.beginPath();
    // 设置画布起点
    ctx.moveTo(x, y);

    canvas.onmousemove = null;
    canvas.onmousemove = function () {
        let moveX = window.event.pageX - offsetLeft;
        let moveY = window.event.pageY - offsetTop;
        let { x, y } = generateLinePoint(moveX, moveY);
        // 绘制线条
        ctx.lineWidth = lineWidth;
        ctx.lineJoin = 'round';
        ctx.lineCap = 'round';
        ctx.strokeStyle = lineColor;
        ctx.lineTo(x, y);
        ctx.stroke();
    };
    canvas.onmouseup = function () {
        // 鼠标抬起时，获取当前canvas画布状态
        // 添加进状态列表中，并且更新状态下标
        // 如果当前处于撤销状态，若使用画笔更新状态，则将当前的最为最新的状态，原先位置之后的状态全部清空
        let imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);

        // 如果此时处于撤销状态，此时再使用画笔，则将之后的状态清空，以刚画的作为最新的画布状态
        if (canvasCurrentHistory < canvasHistory.length) {
            canvasHistory = canvasHistory.slice(0, canvasCurrentHistory);
        }
        canvasHistory.push(imageData);
        canvasCurrentHistory += 1;

        ctx.closePath();

        canvas.onmousemove = null;
        canvas.onmouseup = null;
    };
}

// 橡皮擦模式：监听鼠标事件
function handleEraserMode(downX, downY) {
    let ctx = canvas.getContext('2d');
    if (!wrapper || !canvas || !ctx) {
        return false;
    }

    let offsetTop = canvas.offsetTop;
    let offsetLeft = canvas.offsetLeft;
    downX -= offsetLeft;
    downY -= offsetTop;

    let { x, y } = generateLinePoint(downX, downY);

    ctx.beginPath();
    ctx.moveTo(x, y);

    canvas.onmousemove = null;
    canvas.onmousemove = function () {
        let moveX = window.event.pageX - offsetLeft;
        let moveY = window.event.pageY - offsetTop;

        let { x, y } = generateLinePoint(moveX, moveY);
        ctx.globalCompositeOperation = 'destination-out';
        ctx.lineWidth = lineWidth;
        ctx.strokeStyle = 'rgba(255, 255, 255, 1)';
        ctx.lineTo(x, y);
        ctx.stroke();
    };
    canvas.onmouseup = function () {
        // 保存历史
        let imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
        if (canvasCurrentHistory < canvasHistory.length) {
            canvasHistory = canvasHistory.slice(0, canvasCurrentHistory);
        }
        canvasHistory.push(imageData);
        canvasCurrentHistory += 1;

        // 关闭画布操作流
        ctx.closePath();
        canvas.onmousemove = null;
        canvas.onmouseup = null;
    };
}

// 保存并预览
function handleSave() {
    // 保存文件
    let src = canvas.toDataURL()
    console.log('src: ', src);
    let img = dataURLtoFile(src);
    console.log('img: ', img);

    // 预览
    const previewImg = new Image();
    // 创建一个 fileReader
    const fileReader = new FileReader();
    // 将生成的图片文件读到 fileReader中
    fileReader.readAsDataURL(img);
    fileReader.onload = function () {
        // 将 fileReader.result 设置为 图片的 src
        previewImg.src = this.result;
    }
    let imgs = document.getElementById('previewImg').children
    for (let i = 0; i < imgs.length; i++) {
        document.getElementById('previewImg').removeChild(imgs[i]);
    }
    document.getElementById('previewImg').appendChild(previewImg);
}

window.onload = () => {
    fillImg();
};